#include "WaiterList.h"

class CWaiterListImpl
{
	struct WaitItem
	{
		CMyEvent	myEvent;
		bool		isUsed;

		KeyType		strKey;
		ParamType	param;
	};

	typedef deque<WaitItem *> WaitList;

public:
	CWaiterListImpl();
	~CWaiterListImpl();

	int AddWaitItem(const KeyType &key);

	bool Wait(int nIndex, int nTimeout, ParamType &param);

	bool Signal(const KeyType &key, const ParamType &param);

private:
	WaitList	m_waitList;
	CLock		m_lockWaitList;
};

CWaiterList::CWaiterList()
{
	m_pImpl = new CWaiterListImpl;
}

CWaiterList::~CWaiterList()
{
	if (m_pImpl)
	{
		delete m_pImpl;
		m_pImpl = NULL;
	}
}

int CWaiterList::AddWaitItem(const KeyType &key)
{
	return m_pImpl->AddWaitItem(key);
}

bool CWaiterList::Wait(int nIndex, int nTimeout, ParamType &param)
{
	return m_pImpl->Wait(nIndex, nTimeout, param);
}

bool CWaiterList::Signal(const KeyType &key, const ParamType &param)
{
	return m_pImpl->Signal(key, param);
}

CWaiterListImpl::CWaiterListImpl()
{
	const int nInitSize = 5;

	WaitItem *pItem;
	for (int i = 0; i < nInitSize; i++)
	{
		pItem = new WaitItem;
		pItem->isUsed = false;

		m_waitList.push_back(pItem);
	}
}


CWaiterListImpl::~CWaiterListImpl()
{
	CAutoLock autoLock(&m_lockWaitList);

	for (WaitList::iterator iter = m_waitList.begin(); iter != m_waitList.end(); ++iter)
	{
		delete *iter;
	}

	m_waitList.clear();
}

int CWaiterListImpl::AddWaitItem(const KeyType &key)
{
	int nIndex = 0;
	WaitItem *pItem = NULL;

	{
		CAutoLock autoLock(&m_lockWaitList);

		WaitList::iterator iter = m_waitList.begin();
		for (; iter != m_waitList.end(); ++iter, ++nIndex)
		{
			if (!(*iter)->isUsed)
				break;
		}		

		if (iter == m_waitList.end())
		{
			pItem = new WaitItem;
			pItem->isUsed = false;

			m_waitList.push_back(pItem);
		}
		else
			pItem = *iter;
	}	

	pItem->isUsed = true;
	pItem->strKey = key;

	return nIndex;
}

bool CWaiterListImpl::Wait(int nIndex, int nTimeout, ParamType &param)
{
	if (nIndex < 0 || nIndex >= (int)m_waitList.size())
		return false;
	
	WaitItem *pItem = m_waitList[nIndex];

	int nRet = pItem->myEvent.Wait(nTimeout);
	pItem->isUsed = false;
	param = pItem->param;

	if (nRet == 0)
		return true;
	
	return false;
}

bool CWaiterListImpl::Signal(const KeyType &key, const ParamType &param)
{
	CAutoLock autoLock(&m_lockWaitList);

	WaitList::iterator iter = m_waitList.begin();
	for (; iter != m_waitList.end(); ++iter)
	{
		WaitItem *pItem = *iter;
		if (pItem->isUsed && pItem->strKey == key)
		{
			pItem->param = param;
			pItem->myEvent.Set();

			break;
		}
	}

	if (iter == m_waitList.end())
		return false;

	return true;
}
